﻿#include "CoreData.h"
#include "ConfigData.h"

#include <AsDebug>

CoreData::CoreData()
{
	initCoreData();
	qDebug() << "CoreData Thread:" << this->thread();
}

CoreData::~CoreData()
{
	//delete m_pFirstData;
	delete m_pCoreDataThread;
}

cv::Mat CoreData::normalizeToRange(const cv::Mat& inputMat)
{
	// Find the minimum and maximum values in the inputMat
	double minMat, maxMat;
	cv::Mat output;
	cv::minMaxLoc(inputMat, &minMat, &maxMat);

	// Compute the scaling factor and shift required for normalization
	double scale = 255.0 / (maxMat - minMat);
	double shift = -minMat * scale;

	// Normalize the values in the inputMat to the range 0-255
	inputMat.convertTo(output, CV_8U, scale, shift);
	return output;
}

cv::Rect CoreData::getBox(const cv::Mat& input, double thres)
{
	//cv::Mat binaryImage;
	//threshold(input, binaryImage, thres, 255, cv::THRESH_BINARY);
	//cv::Mat labels, stats, centroids;
	//int numComponents = cv::connectedComponentsWithStats(binaryImage, labels, stats, centroids);
	//std::vector<cv::Rect> boxs;
	//// Find the minimum bounding rectangle for each component (excluding background)
	//for (int i = 1; i < numComponents; ++i) {
	//	// Get the bounding rectangle information from the stats matrix
	//	int left = stats.at<int>(i, cv::CC_STAT_LEFT);
	//	int top = stats.at<int>(i, cv::CC_STAT_TOP);
	//	int width = stats.at<int>(i, cv::CC_STAT_WIDTH);
	//	int height = stats.at<int>(i, cv::CC_STAT_HEIGHT);
	//	// Draw the minimum bounding rectangle on the original image
	//	cv::rectangle(binaryImage, cv::Rect(left, top, width, height), cv::Scalar(255), 2);
	//	boxs.push_back(cv::Rect(left, top, width, height));
	//}
	//cv::rectangle(binaryImage, boxs[0], cv::Scalar(255));
	//return boxs[0];

	cv::Mat binaryImage;
	threshold(input, binaryImage, thres, 255, cv::THRESH_BINARY);
	cv::Mat labels, stats, centroids;
	int numComponents = cv::connectedComponentsWithStats(binaryImage, labels, stats, centroids);
	std::vector<cv::Rect> boxes;

	int largestArea = 0;
	cv::Rect largestBox;

	// Find the minimum bounding rectangle for each component (excluding background)
	for (int i = 1; i < numComponents; ++i) {
		// Get the bounding rectangle information from the stats matrix
		int left = stats.at<int>(i, cv::CC_STAT_LEFT);
		int top = stats.at<int>(i, cv::CC_STAT_TOP);
		int width = stats.at<int>(i, cv::CC_STAT_WIDTH);
		int height = stats.at<int>(i, cv::CC_STAT_HEIGHT);

		int area = width * height;

		// Update the largest rectangle if needed
		if (area > largestArea) {
			largestArea = area;
			largestBox = cv::Rect(left, top, width, height);
		}

		// Draw the minimum bounding rectangle on the original image
		cv::rectangle(binaryImage, cv::Rect(left, top, width, height), cv::Scalar(255), 2);
		boxes.push_back(cv::Rect(left, top, width, height));
	}

	// Draw the largest rectangle on the binary image
	cv::rectangle(binaryImage, largestBox, cv::Scalar(255));

	return largestBox;
}

float CoreData::getNormalvalue(const cv::Mat& inputMat, float input)
{
	double minMat, maxMat;
	cv::minMaxLoc(inputMat, &minMat, &maxMat);

	// Compute the scaling factor and shift required for normalization
	double scale = 255.0 / (maxMat - minMat);

	float output = (input - minMat)*scale;
	return output;
}

//输入CV_32FC1的mat是未映射0-255的深度图，threshold是未映射的深度阈值
cv::Mat CoreData::getLocalMat(const cv::Mat&mat, float threshold, int edgeWidth)
{
	//越界判断
	CV_Assert(mat.type() == CV_32FC1);
	cv::Mat copyMat = mat.clone();
	double maxValue, minValue;
	cv::minMaxLoc(mat, &minValue, &maxValue);
	if (threshold > maxValue || threshold < minValue)
	{

		AsDebug() << "threshold越界";
		return cv::Mat();
	}

	double nomorValue = getNormalvalue(mat, threshold);
	cv::Mat depthMat = normalizeToRange(mat);//生成0-255的灰度
	cv::Rect box1 = getBox(depthMat, nomorValue);//内矩形
	cv::Mat copy = mat.clone();
	cv::Mat innerRecMat = copy(box1);

	if (box1.x - edgeWidth<0 || box1.y - edgeWidth<0 || box1.x + box1.width + edgeWidth>mat.cols || box1.y + box1.height + edgeWidth>mat.rows)
	{
		AsDebug() << "edgeWidth越界";
		return cv::Mat();
	}

	cv::Rect box2(box1.x - edgeWidth, box1.y - edgeWidth, box1.width + 2 * edgeWidth, box1.height + 2 * edgeWidth);//外矩形
	cv::Mat nanMat(box2.height, box2.width, CV_32FC1, std::numeric_limits<double>::quiet_NaN());//生成nan矩阵

	cv::Mat nanMatROI = nanMat(cv::Rect(edgeWidth, edgeWidth, box1.width, box1.height));
	cv::Mat box2roi = copy(cv::Rect(edgeWidth, edgeWidth, box1.width, box1.height));
	//innerRecMat.copyTo(nanMatROI);
	mat.copyTo(nanMatROI);

	for (int y = 0; y < copyMat.rows; y++)
	{
		for (int x = 0; x < copyMat.cols; x++)
		{
			if (copyMat.at<float>(y, x) < threshold) {
				copyMat.at<float>(y, x) = std::numeric_limits<double>::quiet_NaN();
			}
		}

	}




	return copyMat(box2);
}

int CoreData::partition(QList<int> &arr, int low, int high)
{
	int pivot = arr[high]; // Choose the pivot as the last element
	int i = low - 1; // Index of the smaller element

	for (int j = low; j < high; j++) {
		if (arr[j] < pivot) {
			i++;
			arr.swap(i, j);
		}
	}
	arr.swap(i + 1, high);; // Move pivot to its correct position
	return i + 1; // Return the index of pivot
}

void CoreData::quickSort(QList<int> &arr, int low, int high)
{
	if (low < high) {
		int pivotIndex = partition(arr, low, high);
		quickSort(arr, low, pivotIndex - 1);
		quickSort(arr, pivotIndex + 1, high);
	}
}

void CoreData::handleDatas(int index)
{

	qDebug() << "handleDatas  start"<<index;

	//可以取消asthread，在processcore中是多线程
	m_pCoreDataThread->invokeFn([this,index]() {
		//double *datas = m_dataPtrVec[index];
		double *data = getDataPtrWithIndex(index);
		float *ptr = m_mat.ptr<float>(m_matRow++);
		m_mutex.lock();
		for (int i = 0; i < ONCE_DATA_LENGTH; i++)
		{
			ptr[i] = *(data+i);
			m_onceYDataAll << ptr[i];
			m_onceXDataAll << m_xCount++;
			
		}
		m_mutex.unlock();
		//qDebug() << "matRow:" << m_matRow;
		if (m_matRow >= MAT_ROW || m_isTriggerByHardware)
		{
			m_matVec << m_mat;
			//AsDebug() <<"----------------m_mat----------------:" <<m_mat;
			//qDebug() << m_mat.at<float>(100, 100);
			//qDebug() << m_mat.at<float>(300,300);
			//qDebug() << m_mat.at<float>(500, 500);
			//qDebug() << m_mat.at<float>(900, 900);
			//qDebug() << m_mat.at<float>(999, 999);
			m_matRow = 0;
			//m_isTriggerByHardware = false;
			m_numberOfDataMat++;
			//if (m_numberOfDataMat>PtrConfig->paramHardware.imgAccount)
			if (m_numberOfDataMat > 0)
			{
				emit getDatasOfThisHeightOver();
			}
		}
		qDebug() << "handleDatas  Over" << index;
/*		if (!flag)
		{
			emit allowTimerStart();
			flag = true;
		}*/	
		});

}

void CoreData::extrastGirdleMat()
{
	QList<int> keys = m_averageMatMap.keys();
	for (int i = 0; i < keys.size(); ++i)
	{
		int height = keys.at(i);
		cv::Mat mat = m_averageMatMap.value(height);
		mat.convertTo(mat, CV_32FC1);
		//cv::Mat local32 = getLocalMat(mat, 0.01, 10);       滤波参数 为 0.01
		cv::Mat local32 = getLocalMat(mat, 0.07, 10);       //原始参数 为 0.07
		cv::Mat local64;
		local32.convertTo(local64, CV_64FC1);
		m_girldeMatMap.insert(height, local64);
	}
}

void CoreData::initCoreData()
{
	m_pCoreDataThread = new AsThread(this);
	m_mat = cv::Mat(ONCE_DATA_LENGTH, MAT_ROW, CV_32FC1);
	m_pciDataVec.resize(ONCE_DATA_LENGTH * 10);

	//m_pFirstData = new double[ONCE_DATA_LENGTH*10];
	//int interval = ONCE_DATA_LENGTH;
	//double *dataPtr0 = m_pFirstData;
	//for (int i = 0; i < 10; i++)
	//{
	//	m_dataPtrVec << dataPtr0;
	//	dataPtr0 += interval;
	//}

	for (int i = 0;i<ONCE_DATA_LENGTH;i++)
	{
		m_constXData << i;
	}
	qDebug() << "CoreData Init Finished...";
}

void CoreData::shiftTriggerStateByHardware()
{
	if (m_isTriggerByHardware)
	{
		m_isTriggerByHardware = false;
		return;
	}
	if (!m_isTriggerByHardware)
	{
		m_isTriggerByHardware = true;
		return;
	}
}

void CoreData::setMapListItem(int height, QListWidgetItem *item)
{
	m_listwidgetMap.insert(height, item);
}

QListWidgetItem* CoreData::getListItemWithHeight(int height)
{
	return m_listwidgetMap.value(height);
}

int CoreData::getHeightWithListItem(QListWidgetItem *item)
{
	return m_listwidgetMap.key(item);
}

QMap<int, QListWidgetItem*> CoreData::getListItemMap()
{
	return m_listwidgetMap;
}

void CoreData::setMatDataMap(int height, QVector<cv::Mat> matVec)
{
	m_itemDataMatsMap.insert(height, matVec);
}

QMap<int,QVector<cv::Mat>> CoreData::getMatDatasMap()
{
	return m_itemDataMatsMap;
}

QMap<int, cv::Mat> CoreData::getAverageMatMap()
{
	return m_averageMatMap;
}

void CoreData::insertAverageMatMap(int height, cv::Mat mat)
{
	m_averageMatMap.insert(height, mat);
}

QMap<int,QVector<QVector3D>> CoreData::getVec3DMap()
{
	return m_vec3DMap;
}

void CoreData::insertVec3DMap(int height, QVector<QVector3D> vec3dVec)
{
	m_vec3DMap.insert(height, vec3dVec);
}

QVector<double> CoreData::getOnceAllXDataWithHeight(int height)
{
	return m_itemXDataVecMap.value(height);
}

QVector<double> CoreData::getOnceAllYDataWithHeight(int height)
{
	return m_itemYDataVecMap.value(height);
}

QVector<double> CoreData::getConstXData()
{
	return m_constXData;
}

double * CoreData::getDataPtrWithIndex(int index)
{
	//return m_dataPtrVec[index];

	return m_pciDataVec.data() + index * ONCE_DATA_LENGTH;
}

QVector<double> CoreData::getVecYDatasWithIndex(int index)
{
	QVector<double> yDatasVec;
	double * data = getDataPtrWithIndex(index);
	qDebug()<<"double* First Data" << data[0];
	for (int i = 0;i<ONCE_DATA_LENGTH;i++)
	{
		yDatasVec << data[i];
	}
	return yDatasVec;
}

void CoreData::updateOnceCollectDatasWithHeight()
{
	int height = m_currentHeight;
	m_itemXDataVecMap.insert(height, m_onceXDataAll);
	m_itemYDataVecMap.insert(height, m_onceYDataAll);
	m_itemDataMatsMap.insert(height, m_matVec);
	//AsDebug() << "----------------m_matVEC0----------------:" << m_matVec[0];
	//qDebug() << m_matVec[0].at<float>(100, 100);
	//qDebug() << m_matVec[0].at<float>(300, 300);
	//qDebug() << m_matVec[0].at<float>(500, 500);
	//qDebug() << m_matVec[0].at<float>(900, 900);
	//qDebug() << m_matVec[0].at<float>(999, 999);

	//清空中间容器
	m_matRow = 0;
	m_xCount = 0;
	m_onceYDataAll.clear();
	//XDataAll可优化
	m_onceXDataAll.clear();
	m_matVec.clear();
}


void CoreData::sortHeightList()
{
	m_heightList = m_listwidgetMap.keys();
	int low = 0;
	int high = m_heightList.size() - 1;
	quickSort(m_heightList, low, high);
}

QList<int> CoreData::getSortHeightList()
{
	return m_heightList;
}

void CoreData::setCurrentHeight(int height)
{
	m_currentHeight = height;
}

int CoreData::getCurrentHeight()
{
	return m_currentHeight;
}

//QVector<double> CoreData::getVecXDatasWithIndex(int index)
//{
//	return m_itemXDataVecMap.value(index);
//}
